﻿/**************************************************************************
创建时间:	2013/4/14
作	  者:	张存
邮 	  箱:	zhangcunliang@126.com

描	述：
记	录：
    2020.11.10 编辑框文本优化
    2020.11.13 显示行号后 按索引取值的bug，注意：其它扩展的信息不要保存列索引，显示行号会替换掉
    2020.11.19 增加获取 过滤数据源 GetDataSource
    2020.11.23 增加合并单元格的实现(原控件方式不再使用)
    2020.12.11 实现新的单元格编辑框的实现，原编辑单元格实现作废
    2023.9.28  增加分组的画大括号的实现
    2024.3.8   优化了输入编辑框的实现，支持一个文本框控件对应多列
***************************************************************************/
using ASmile.Extend;
using ASmile.Helpers;
using ASmile.ORM.Entitys;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;

namespace ASmile.Win.Controls
{
    /// <summary>
    /// 自定义gridview
    /// </summary>
    public class GridView : DataGridView
    {
        /// <summary>
        /// 默认构造
        /// </summary>
        public GridView()
        {
            InitializeComponent();
        }

        void InitializeComponent()
        {
            this.AllowUserToAddRows = false;
            this.AllowUserToDeleteRows = false;
            this.AllowUserToResizeRows = false;
            this.AutoGenerateColumns = false; //自动创建列
            this.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            this.ReadOnly = true;
            //this.RowHeadersVisible = false; //行前面那列
            this.MultiSelect = false; //多选
            this.BackgroundColor = Color.White;
            this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;

            //初始化样式
            InitiStyle();
        }
        /// <summary>
        /// 当数据源发生变化时，处理view列、
        /// </summary>
        protected override void OnDataSourceChanged(EventArgs e)
        {
            base.OnDataSourceChanged(e);
            SetLastSelected();
            LastRowCount = RowCount;
            SetViewColumnDisplay();
            LastSelectionRowIndex = -1;

            //InputEditHide();
        }
        /// <summary>
        /// 绑定数据源之后，进行行号，view列、默认选中的操作
        /// 合并单元格处理(将控件附着上)
        /// </summary>
        protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e)
        {
            base.OnDataBindingComplete(e);
            //TODO:这里会执行两次，还不明原因 (因为调用BindDataSource 多执行了一个 = null)
            //行号必须放到这里，不要尝试放到 OnDataSourceChanged 了
            if (DataSource == null) return;
            SetColumnRowNo();
        }
        /// <summary>
        /// 设置选中行
        /// </summary>
        protected override void OnSelectionChanged(EventArgs e)
        {
            base.OnSelectionChanged(e);
            IsSelectChange = true;
        }
        /// <summary>
        /// cell 点击前触发，
        /// 1. 选中行的特殊处理
        /// 2. 列按钮事件
        /// 3. checkbox 点击单元格选中
        /// 4. 点击进入编辑
        /// 5. 对于合并列单击选中相同组的行
        /// </summary>
        protected override void OnCellClick(DataGridViewCellEventArgs e)
        {
            base.OnCellClick(e);
            SetSelectionAndClickEvent(e);
            SetButtonClickEvent(e);
            SetCheckBoxCellClickEvent(e);
            //InputEditInit(e.ColumnIndex, e.RowIndex); // 2020.12.10 新的实现，测试完成后替换上一行代码
            MergeSelected(e);
        }
        /// <summary>
        /// 进入单元格显示自定义编辑控件
        /// </summary>
        protected override void OnCellEnter(DataGridViewCellEventArgs e)
        {
            base.OnCellEnter(e);
        }
        /// <summary>
        /// 本地刷新数据源
        /// </summary>
        public void RefreshDataSource()
        {
            object data = DataSource;
            DataSource = null;
            DataSource = data;
        }

        #region 样式处理

        bool _UseControlStyle = true;
        /// <summary>
        /// 是否使用控件本身的样式,
        /// true:将设置成系统默认样式
        /// </summary>
        [Description("是否使用控件本身的样式,true:将设置成系统默认样式"), Category("zhcun GridView"), Browsable(true)]
        public bool UseControlStyle
        {
            get { return _UseControlStyle; }
            set
            {
                if (value)
                {
                    InitiStyle();
                }
                _UseControlStyle = value;
            }
        }
        /// <summary>
        /// 初始化GridView样式
        /// </summary>
        public void InitiStyle()
        {
            this.BackgroundColor = Color.Snow;
            this.AlternatingRowsDefaultCellStyle.BackColor = SystemColors.Control;
            this.RowsDefaultCellStyle.BackColor = Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
        }

        #endregion

        #region view列的实现 2021.5.7 更新

        const string VIEW_COLUMN_FLAG = "[-VIEW]";

        /// <summary>
        /// 视图对应字典,key:列名, 2级key:原值,2级value:对应值
        /// </summary>
        public Dictionary<string, Dictionary<string, string>> ViewConfigDict { get; private set; }
        /// <summary>
        /// 视图对应字典，已委托传递取值的方式
        /// </summary>
        public Dictionary<string, Func<string, string>> ViewConfigScheme { get; private set; }
        /// <summary>
        /// 增加一个对应列及值要显示的内容
        /// </summary>
        /// <param name="colName">列名</param>
        /// <param name="srcValue">原显示的列值</param>
        /// <param name="viewValue">对应显示的值</param>
        public void AddViewColumn(string colName, string srcValue, string viewValue)
        {
            if (!this.Columns.Contains(colName)) return;
            if (ViewConfigDict == null)
            {
                ViewConfigDict = new Dictionary<string, Dictionary<string, string>>();
            }

            Dictionary<string, string> vDict;

            if (ViewConfigDict.ContainsKey(colName))
            {
                vDict = ViewConfigDict[colName];
            }
            else
            {
                vDict = ViewConfigDict[colName] = new Dictionary<string, string>();
            }

            vDict[srcValue] = viewValue;

            //Dictionary<string, string> viewData = new Dictionary<string, string>();
            //viewData[srcValue] = viewValue;
            //ViewConfigDict[colName] = viewData;

            AddViewColumn(colName, (srcVal) =>
            {
                string defVal = null;

                if (!ViewConfigDict[colName].ContainsKey(srcVal)) return defVal;

                return ViewConfigDict[colName][srcVal];

                //if (ViewConfigDict[colName][srcVal] == srcVal)
                //{
                //    return ViewConfigDict[colName][srcVal];
                //}
                //return defVal;
            });
        }

        public void AddViewColumn(string colName, Func<string, string> ViewScheme)
        {
            if (!this.Columns.Contains(colName)) return;
            if (ViewScheme == null) return;
            if (ViewConfigScheme == null) ViewConfigScheme = new Dictionary<string, Func<string, string>>();
            if (ViewConfigScheme.ContainsKey(colName)) return;
            ViewConfigScheme[colName] = ViewScheme;

            DataGridViewColumn srcCol = this.Columns[colName];
            srcCol.Visible = false;

            DataGridViewTextBoxColumn newCol = new DataGridViewTextBoxColumn();
            newCol.HeaderText = srcCol.HeaderText;
            newCol.Name = srcCol.Name + VIEW_COLUMN_FLAG;
            newCol.ReadOnly = true;
            newCol.Width = srcCol.Width;
            newCol.Visible = true;
            newCol.DisplayIndex = srcCol.DisplayIndex;
            newCol.CellTemplate.ValueType = typeof(string);
            newCol.ValueType = typeof(string);
            newCol.Name = srcCol.Name + VIEW_COLUMN_FLAG;
            newCol.DefaultCellStyle.Alignment = srcCol.DefaultCellStyle.Alignment;
            newCol.AutoSizeMode = srcCol.AutoSizeMode;
            newCol.Frozen = srcCol.Frozen;
            Columns.Add(newCol);
        }
        /// <summary>
        /// 设置view列的显示值
        /// </summary>
        void SetViewColumnDisplay()
        {
            if (!(ViewConfigScheme?.Count > 0 || ViewConfigDict?.Count > 0))
            {
                return;
            }

            object cellValue;
            string viewColName;
            foreach (DataGridViewRow row in Rows)
            {
                foreach (var item in ViewConfigScheme)
                {
                    if (!Columns.Contains(item.Key)) continue;
                    cellValue = row.Cells[item.Key].Value;
                    if (cellValue == null || cellValue == DBNull.Value) cellValue = string.Empty;

                    var newVal = item.Value(cellValue.ToString());
                    viewColName = item.Key + VIEW_COLUMN_FLAG;
                    row.Cells[viewColName].Value = newVal;
                }
            }
        }


        #endregion

        #region 行号显示

        const string RowNoColumnName = "{Row-Number}";
        /// <summary>
        /// 行号类型
        /// </summary>
        public enum RowNoStyle
        {
            /// <summary>
            /// 行头画一列
            /// </summary>
            Header,
            /// <summary>
            /// 增加一个列
            /// </summary>
            CustomColumn,
        }

        /// <summary>
        /// 行号默认显示的背景颜色
        /// </summary>
        Color RowNoBackColor { set; get; } = Color.Snow; //SystemColors.Control; // Color.Lavender; //Color.PowderBlue;//Color.AliceBlue;
        /// <summary>
        /// 行号最小列宽，默认50
        /// </summary>
        int RowNoWidth { set; get; } = 50;

        /// <summary>
        /// 是否显示行号
        /// </summary>
        [Description("是否显示行号"), Category("ZCGridView"), Browsable(true)]
        public bool DisplayRowNo { set; get; } = false;
        /// <summary>
        /// 显示行号的类型
        /// </summary>
        [Description("显示行号的类型"), Category("ZCGridView"), Browsable(true)]
        public RowNoStyle DisplayRowNoStyle { set; get; } = RowNoStyle.CustomColumn;

        /// <summary>
        /// 重画行号
        /// </summary>
        protected override void OnRowPostPaint(DataGridViewRowPostPaintEventArgs e)
        {
            base.OnRowPostPaint(e);

            if (!DisplayRowNo || DisplayRowNoStyle != RowNoStyle.Header) return;

            Rectangle rectangle = new Rectangle(e.RowBounds.Location.X,
                e.RowBounds.Location.Y,
                this.RowHeadersWidth - 4,
                e.RowBounds.Height);
            TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(),
            this.RowHeadersDefaultCellStyle.Font,
                rectangle,
                this.RowHeadersDefaultCellStyle.ForeColor,
                TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
        }
        /// <summary>
        /// 初始化列行号
        /// </summary>
        void SetColumnRowNo()
        {
            if (!DisplayRowNo || DisplayRowNoStyle != RowNoStyle.CustomColumn) return;

            if (!Columns.Contains(RowNoColumnName))
            {
                var col = new DataGridViewTextBoxColumn();
                col.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
                col.HeaderText = "";
                //col.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
                col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
                col.ReadOnly = true;
                col.Name = RowNoColumnName;

                col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                col.Width = RowNoWidth;
                col.Frozen = true;
                col.DefaultCellStyle.BackColor = RowNoBackColor;
                col.DefaultCellStyle.SelectionBackColor = RowNoBackColor;
                col.DefaultCellStyle.SelectionForeColor = Color.Black;

                Columns.Insert(0, col);
                this.RowHeadersVisible = false;
            }

            for (int i = 0; i < RowCount; i++)
            {
                Rows[i].Cells[RowNoColumnName].Value = (i + 1).ToString();
                Rows[i].Cells[RowNoColumnName].Style.BackColor = RowNoBackColor;
            }
        }

        #endregion

        #region 自动选中行的实现

        /// <summary>
        /// 上次行数，用于判断数据源是否一致
        /// </summary>
        [Browsable(false)]
        public int LastRowCount { private set; get; }

        /// <summary>
        /// 返回上次选中的行索引，引用重置选中记录
        /// </summary>
        [Browsable(false)]
        public int LastSelectionRowIndex { private set; get; }

        void SetLastSelected()
        {
            if (MultiSelect) return;

            if (LastRowCount == RowCount && LastSelectionRowIndex >= 0 && LastSelectionRowIndex <= Rows.Count - 1)
            {
                Rows[LastSelectionRowIndex].Selected = true;
            }
            else
            {
                foreach (DataGridViewRow item in SelectedRows)
                {
                    item.Selected = false;
                }
            }
        }

        #endregion

        #region 共通常用方法

        /// <summary>
        /// 绑定数据源
        /// </summary>
        public void BindDataSource(object dataSource)
        {
            this.DataSource = null;
            if (dataSource is System.Collections.IList listData)
            {
                //如果绑定的 new 过的 List但是没有数据点击单元格会报错
                if (listData.Count == 0) return;
            }
            this.DataSource = dataSource;
        }
        /// <summary>
        /// 返回第一列的所有选中行
        /// </summary>
        public object[] GetAllSelectedItem()
        {
            if (this.SelectedRows.Count > 0)
            {
                object[] objArr = new object[this.SelectedRows.Count];
                for (int i = 0; i < SelectedRows.Count; i++)
                {
                    objArr[i] = SelectedRows[i].Cells[0].Value;
                }
                return objArr;
            }
            return null;
        }
        /// <summary>
        /// 返回指定列的所有的选中行
        /// </summary>
        public object[] GetAllSelectedItem(string columnName)
        {
            if (this.SelectedRows.Count > 0)
            {
                if (!Columns.Contains(columnName))
                {
                    return null;
                }
                object[] objArr = new object[this.SelectedRows.Count];
                for (int i = 0; i < SelectedRows.Count; i++)
                {
                    objArr[i] = SelectedRows[i].Cells[columnName].Value;
                }
                return objArr;
            }
            return null;
        }
        /// <summary>
        /// 返回选中的首行的指定列的值,未获取到返回null
        /// </summary>
        public object GetFirstSelectItem(string columnName)
        {
            object[] selItem = GetAllSelectedItem(columnName);
            if (selItem != null && selItem.Length > 0)
            {
                return selItem[0];
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 根据属性名获取列对象
        /// </summary>
        public DataGridViewColumn GetColumnByPropertyName(string dataPropertyName)
        {
            foreach (DataGridViewColumn item in Columns)
            {
                if (item.DataPropertyName.StringEquals(dataPropertyName))
                {
                    return item;
                }
            }
            return null;
        }
        /// <summary>
        /// 获取单元格值，根据索引
        /// </summary>
        public object GetCellValue(int rowIndex, int columnIndex)
        {
            object cellValue = Rows[rowIndex].Cells[columnIndex].Value;
            return cellValue;
        }
        /// <summary>
        /// 获取单元格值，根据列名
        /// </summary>
        public object GetCellValue(int rowIndex, string columnsName)
        {
            object cellValue = Rows[rowIndex].Cells[columnsName].Value;
            return cellValue;
        }
        /// <summary>
        /// 获取单元格值的泛型实现，根据cell
        /// </summary>
        public T GetCellValue<T>(DataGridViewCell cell)
        {
            return GetCellValue<T>(cell.RowIndex, cell.ColumnIndex);
        }
        /// <summary>
        /// 获取单元格值的泛型实现，根据索引
        /// </summary>
        public T GetCellValue<T>(int rowIndex, int columnIndex)
        {
            object obj = GetCellValue(rowIndex, columnIndex);
            if (obj != null && obj != DBNull.Value)
            {
                if (default(T) is ValueType)
                {
                    //T t = (T)Convert.ChangeType(obj, obj.GetType());
                    try
                    {
                        T t = (T)Convert.ChangeType(obj, typeof(T));
                        return t;
                    }
                    catch (Exception)
                    {
                        return default;
                    }
                }
                else
                {
                    T t = (T)obj;
                    return t;
                }

            }
            return default(T);
        }
        /// <summary>
        /// 获取单元格值的泛型实现，根据列名
        /// </summary>
        public T GetCellValue<T>(int rowIndex, string columnName)
        {
            if (!Columns.Contains(columnName)) return default(T);
            var colIndex = Columns[columnName].Index;
            return GetCellValue<T>(rowIndex, colIndex);
        }
        /// <summary>
        /// 根据列名获取选中行单元格值的泛型实现，
        /// </summary>
        public T GetCellValue<T>(string columnName)
        {
            var colIndex = Columns[columnName].Index;
            if (SelectedRows.Count == 0) return default(T);

            return GetCellValue<T>(SelectedRows[0].Index, colIndex);
        }
        /// <summary>
        /// 获取单元格值，根据数据源属性名
        /// </summary>
        public object GetCellValueByPropertyName(int rowIndex, string dataPropertyName)
        {
            var colIndex = GetColumnByPropertyName(dataPropertyName);
            return GetCellValue(rowIndex, colIndex.Index);
        }
        /// <summary>
        /// 获取单元格值的泛型实现，根据数据源属性名
        /// </summary>
        public T GetCellValueByPropertyName<T>(int rowIndex, string dataPropertyName)
        {
            var col = GetColumnByPropertyName(dataPropertyName);
            return GetCellValue<T>(rowIndex, col.Index);
        }
        /// <summary>
        /// 设置指定单元格的值，根据列索引
        /// </summary>
        public bool SetCellValue(int rowIndex, int columnIndex, object cellValue)
        {
            if (rowIndex < 0 || columnIndex < 0 || Columns.Count <= columnIndex) return false;
            Rows[rowIndex].Cells[columnIndex].Value = cellValue;
            return true;
        }
        /// <summary>
        /// 设置指定单元格的值，根据列名
        /// </summary>
        public bool SetCellValue(int rowIndex, string columnName, object cellValue)
        {
            if (!Columns.Contains(columnName)) return false;
            var col = Columns[columnName];
            return SetCellValue(rowIndex, col.Index, cellValue);
        }
        /// <summary>
        /// 设置指定单元格的值，根据 数据源属性名
        /// </summary>
        public bool SetCellValueByPropertyName(int rowIndex, string dataPropertyName, object cellValue)
        {
            var col = GetColumnByPropertyName(dataPropertyName);
            return SetCellValue(rowIndex, col.Index, cellValue);
        }
        /// <summary>
        /// 设置指定列索引的所有行的单元格值, 最后调用 EndEdit()
        /// 2022.4.18 改为默认修改当前行的值
        /// 2023.4.8  上次修改了只更新当前行，今天又加了个方法 SetCellValueAll
        /// </summary>
        public bool SetCellValue(int columnIndex, object cellValue)
        {
            if (columnIndex < 0) return false;
            if (RowCount <= 0) return false;
            if (SelectedRows?.Count > 0)
            {
                SetCellValue(this.SelectedRows[0].Index, columnIndex, cellValue);
            }
            EndEdit();
            return true;
        }
        /// <summary>
        /// 设置指定列名的所有行的单元格值, 最后调用 EndEdit()
        /// </summary>
        public bool SetCellValue(string columnName, object cellValue)
        {
            if (!Columns.Contains(columnName)) return false;
            var col = Columns[columnName];
            return SetCellValue(col.Index, cellValue);
        }
        /// <summary>
        /// 设置指定列索引的所有行的单元格值, 最后调用 EndEdit()
        /// 2023.4.8 增加，之前改了不是所有行 的 SetCellValue ，可能有业务修改导致，增加一个来实现
        /// </summary>
        public bool SetCellValueAll(int columnIndex, object cellValue)
        {
            if (columnIndex < 0) return false;
            if (RowCount <= 0) return false;
            for (int i = 0; i < RowCount; i++)
            {
                SetCellValue(i, columnIndex, cellValue);
            }
            EndEdit();
            return true;
        }
        /// <summary>
        /// 设置指定列索引的所有行的单元格值, 最后调用 EndEdit()
        /// 2023.4.8 增加，之前改了不是所有行 的 SetCellValue ，可能有业务修改导致，增加一个来实现
        /// </summary>
        public bool SetCellValueAll(string colName, object cellValue)
        {
            if (!Columns.Contains(colName)) return false;
            var col = Columns[colName];
            return SetCellValueAll(col.Index, cellValue);
        }
        /// <summary>
        /// 设置指定数据源名列的所有行的单元格值
        /// </summary>
        public bool SetCellValueByPropertyName(string dataPropertyName, object cellValue)
        {
            var col = GetColumnByPropertyName(dataPropertyName);
            if (col == null) return false;
            return SetCellValue(col.Index, cellValue);
        }
        /// <summary>
        /// 根据列值的匹配选中行,指定是否多选,isMultiSelect为false则只选中第一个匹配值,指定是否用正则表达式匹配
        /// </summary>
        public bool SelectedRow(string colName, object colValue, bool isMultiSelect, out int rowIndex, bool isRegexMatch = false)
        {
            foreach (DataGridViewRow item in this.SelectedRows)
            {
                item.Selected = false;
            }
            rowIndex = -1;
            if (!this.Columns.Contains(colName)) return false;
            if (isMultiSelect && !MultiSelect)
            {
                MultiSelect = true;
            }

            bool r = false;
            bool matchOk;
            for (int i = 0; i < this.Rows.Count; i++)
            {
                matchOk = false;
                object cellValue = this.Rows[i].Cells[colName].Value;
                if (cellValue == null) continue;
                //if (cellValue.ToString() == colValue)
                //{
                //    matchOk = true;
                //}
                if (colValue.Equals(cellValue))
                {
                    matchOk = true;
                }
                else if (isRegexMatch)
                {
                    string regexStr = colValue.ToString();
                    if (RegexHelper.Check(cellValue.ToString(), regexStr))
                    {
                        matchOk = true;
                    }
                }
                //if (matchOk)
                if (matchOk)
                {
                    r = true;
                    rowIndex = i;
                    this.Rows[i].Selected = true;
                    if (!isMultiSelect)
                    {
                        break;
                    }
                }
            }
            return r;
        }

        public bool SelectedRow(string colName, object colValue, bool isMultiSelect, bool isRegexMatch = false)
        {
            return SelectedRow(colName, colValue, isMultiSelect, out _, isRegexMatch);
        }
        /// <summary>
        /// 单行选中，并返回选中行的行索引
        /// </summary>
        public int SelectedRow(string colName, object colValue)
        {
            SelectedRow(colName, colValue, false, out int rowIndex, false);
            if (rowIndex >= 0)
            {
                FirstDisplayedScrollingRowIndex = rowIndex;
            }
            return rowIndex;
        }
        /// <summary>
        /// 设置所有列是否为只读
        /// </summary>
        public void SetColumnReadOnly(bool isReadOnly = true)
        {
            for (int i = 0; i < Columns.Count; i++)
            {
                Columns[i].ReadOnly = isReadOnly;
            }
        }
        /// <summary>
        /// 获取当前选中行的绑定数据行(非DataGrid行)
        /// </summary>
        /// <typeparam name="T">DataRow或它的子类</typeparam>
        /// <param name="rowIndex">行索引</param>
        /// <returns>返回一个行对象</returns>
        public T GetSelectedRowData<T>(int rowIndex) where T : DataRow
        {
            if (rowIndex < 0) return null;
            DataRowView drv = (DataRowView)this.Rows[rowIndex].DataBoundItem;
            T row = (T)drv.Row;
            return row;
        }
        /// <summary>
        /// 获取当前选中行所绑定的数据源数据
        /// </summary>
        /// <typeparam name="T">DataRow或它的子类</typeparam>
        /// <returns>返回一个DataRow对象</returns>
        public T GetSelectedRowData<T>() where T : DataRow
        {
            var selIndex = GetSelectedRowIndex();
            return GetSelectedRowData<T>(selIndex);
        }
        /// <summary>
        /// 获取当前选中行的绑定数据行(非DataGrid行)
        /// </summary>        
        /// <param name="rowIndex">行索引</param>
        /// <returns>返回一个DataRow</returns>
        public DataRow GetSelectedRowData(int rowIndex)
        {
            return GetSelectedRowData<DataRow>(rowIndex);
        }
        /// <summary>
        /// 获得当前选中行的数据源数据
        /// </summary>
        public DataRow GetSelectedRowData()
        {
            //if (this.SelectedRows.Count == 0) return null;
            //int selRowIndex = this.SelectedRows[0].Index;
            var selRowIndex = GetSelectedRowIndex();
            return GetSelectedRowData(selRowIndex);
        }
        /// <summary>
        /// 获取选中行的DataRow 的指定列的值
        /// </summary>
        public T GetSelectedRowCell<T>(string colName)
        {
            var dr = GetSelectedRowData();
            var r = ReflectionHelper.GetPropertyValue<T>(dr, colName);
            return r;
        }
        /// <summary>
        /// 获取选中行的DataRow 的指定行列的值
        /// </summary>
        public T GetSelectedRowCell<T>(int rowIndex, string colName)
        {
            var dr = GetSelectedRowData(rowIndex);
            var r = ReflectionHelper.GetPropertyValue<T>(dr, colName);
            return r;
        }
        /// <summary>
        /// 获取所有选中行
        /// </summary>
        public T[] GetSelectedAllRow<T>() where T : class, new()
        {
            List<int> rowList = new List<int>();
            if (SelectedRows.Count > 0)
            {
                foreach (DataGridViewRow item in SelectedRows)
                {
                    rowList.Add(item.Index);
                }
            }
            else
            {
                foreach (DataGridViewCell item in SelectedCells)
                {
                    if (rowList.Contains(item.RowIndex)) continue;
                    rowList.Add(item.RowIndex);
                }
            }
            if (rowList.Count == 0)
            {
                return null;
            }
            T[] arr = new T[rowList.Count];
            int i = 0;
            foreach (var rowIndex in rowList)
            {
                arr[i++] = GetSelectedClassData<T>(rowIndex);
            }
            return arr;
        }
        /// <summary>
        /// 是否使用缓冲区效果
        /// </summary>
        public void SetDoubleBuffered(bool val)
        {
            DoubleBuffered = val;
        }
        /// <summary>
        /// 返回当前绑定数据源的一行数据的实体类对象
        /// </summary>
        /// <typeparam name="T">实体类对象类型</typeparam>
        /// <param name="rowIndex">行索引</param>
        /// <returns>返回实体类对象</returns>
        public T GetSelectedClassData<T>(int rowIndex) where T : class, new()
        {
            if (rowIndex < 0) return null;
            if (rowIndex >= this.Rows.Count) return null;
            object dataBoundItem = this.Rows[rowIndex].DataBoundItem;
            if (dataBoundItem == null) return null;
            T rowObj;
            if (dataBoundItem is T)
            {
                rowObj = dataBoundItem as T;
            }
            else if (this.Rows[rowIndex].DataBoundItem is DataRowView)
            {
                //这个是支持把一个绑定了DataTable数据源的行转换成一个实体类
                DataRowView drv = this.Rows[rowIndex].DataBoundItem as DataRowView;
                rowObj = new T();
                ReflectionHelper.SetPropertyValue(rowObj, drv.Row);
            }
            else
            {
                //支持把相同属性的对象根据行赋值
                rowObj = new T();
                ReflectionHelper.SetPropertyValue(rowObj, dataBoundItem);
            }
            if (rowObj is EntityBase dbModel)
            {
                dbModel.ClearChangedState();
            }
            return rowObj;
        }
        /// <summary>
        /// 获取指定行数据源
        /// </summary>
        public bool GetSelectedClassData<T>(int rowIndex, ref T model)
        {
            if (rowIndex < 0) return false;
            if (rowIndex >= this.Rows.Count) return false;
            object dataBoundItem = this.Rows[rowIndex].DataBoundItem;
            if (dataBoundItem == null) return false;
            if (dataBoundItem is T)
            {
                model = (T)dataBoundItem;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 输出一个对象
        /// </summary>
        public bool GetSelectedClassData<T>(ref T model)
        {
            if (this.SelectedRows.Count == 0) return false;
            int selIndex = this.SelectedRows[0].Index;
            return GetSelectedClassData<T>(selIndex, ref model);
        }
        /// <summary>
        /// 获取当前选中行（多个选择只取第一个）的行索引
        /// </summary>
        public int GetSelectedRowIndex()
        {
            int selIndex;
            if (this.SelectedRows.Count == 0)
            {
                if (SelectedCells.Count == 0)
                {
                    return -1;
                }
                selIndex = SelectedCells[0].RowIndex;
            }
            else
            {
                selIndex = this.SelectedRows[0].Index;
            }
            return selIndex;
        }
        /// <summary>
        /// 获取当前选中行绑定的数据源
        /// </summary>
        /// <typeparam name="T">绑定数据源的列</typeparam>
        /// <returns></returns>
        public T GetSelectedClassData<T>() where T : class, new()
        {
            int selIndex = GetSelectedRowIndex();
            return GetSelectedClassData<T>(selIndex);
        }

        public bool GetSelectedClassData<T>(out T[] modelArr) where T : class, new()
        {
            if (this.SelectedRows.Count == 0)
            {
                modelArr = null;
                return false;
            }
            modelArr = new T[SelectedRows.Count];
            for (int i = 0; i < SelectedRows.Count; i++)
            {
                int selIndex = SelectedRows[i].Index;
                modelArr[i] = GetSelectedClassData<T>(selIndex);
            }
            return true;
        }
        /// <summary>
        /// 获取指定行的选中项对象，返回结果：数据源为DataTable时： DataRow 或者 List《T》时 返回 T
        /// </summary>
        public object GetSelectedItemData(int rowIndex)
        {
            if (rowIndex < 0) return null;
            if (rowIndex >= this.Rows.Count) return null;
            object dataBoundItem = this.Rows[rowIndex].DataBoundItem;
            if (dataBoundItem is DataRowView drv)
            {
                return drv.Row;
            }
            return dataBoundItem;
        }
        /// <summary>
        /// 获取第一个选中项的行数据，datarow或者object
        /// </summary>
        /// <returns></returns>
        public object GetSelectedItemData()
        {
            if (this.SelectedRows.Count == 0) return null;
            int selIndex = this.SelectedRows[0].Index;
            return GetSelectedItemData(selIndex);
        }
        /// <summary>
        /// 当数据源为List时，通过 predicate 来匹配数据源
        /// </summary>
        public IEnumerable<TSource> GetDataSource<TSource>(Func<TSource, bool> predicate)
        {
            if (!(DataSource is List<TSource> data)) return null;
            return data.Where(predicate);
        }
        /// <summary>
        /// 判断数据源指定匹配是否存在
        /// </summary>
        public bool DataSourceExists<TSource>(Predicate<TSource> match)
        {
            if (!(DataSource is List<TSource> data)) return false;
            return data.Exists(match);
        }
        /// <summary>
        /// 移除指定数据项，并刷新显示
        /// </summary>
        public bool DelDataSource(object item)
        {
            if (DataSource is System.Collections.IList data)
            {
                data.Remove(item);
                BindDataSource(data);
                Refresh();
                return true;
            }
            return false;
        }
        /// <summary>
        /// 移除指定匹配的数据项，并刷新显示
        /// </summary>
        public bool DelDataSource<TSource>(Predicate<TSource> match)
        {
            if (!(DataSource is List<TSource> data)) return false;

            int count = data.RemoveAll(match);

            if (count > 0)
            {
                BindDataSource(data);
                Refresh();
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 增加数据源
        /// </summary>
        public bool AddDataSource<TSource>(object item, bool isDesc = false, bool onlyAdd = false)
            where TSource : class, new()
        {
            if (typeof(TSource) != item.GetType())
            {
                TSource m = new TSource();
                ReflectionHelper.CopyObject(m, item);
                return AddDataSource(m, isDesc, onlyAdd);
            }
            else
            {
                return AddDataSource(item as TSource, isDesc, onlyAdd);
            }
        }
        /// <summary>
        /// 增加指定数据项，并刷新显示，isDesc ：是否插入首行,仅
        /// </summary>
        public bool AddDataSource<TSource>(TSource item, bool isDesc = false, bool onlyAdd = false)
            where TSource : class, new()
        {
            System.Collections.IList rList; //必须使用这个IList 2021.5.21
            if (DataSource == null)
            {
                rList = new List<TSource>();
            }
            else
            {
                //rList = DataSource as List<TSource>;
                rList = DataSource as System.Collections.IList;
            }
            if (rList == null) return false;
            if (isDesc)
            {
                rList.Insert(0, item);
            }
            else
            {
                rList.Add(item);
            }
            if (!onlyAdd || DataSource == null)
            {
                BindDataSource(rList);
                if (isDesc) SetSelectedRowCore(0, true);
                else SetSelectedRowCore(rList.Count - 1, true);
            }
            return true;
        }

        public bool AddDataSource<TSource>(List<TSource> itemList, bool isDesc = false, bool onlyAdd = false)
        {
            if (itemList == null) return false;
            if (DataSource == null)
            {
                DataSource = itemList;
                SetSelectedRowCore(0, true);
                return true;
            }

            if (!(DataSource is System.Collections.IList data)) return false;
            if (isDesc)
            {
                foreach (var item in itemList)
                {
                    data.Insert(0, item);
                }
            }
            else
            {
                foreach (var item in itemList)
                {
                    data.Add(item);
                }
            }
            if (!onlyAdd)
            {
                BindDataSource(data);
                if (isDesc) SetSelectedRowCore(0, true);
                else SetSelectedRowCore(data.Count - 1, true);
            }
            return true;
        }

        #endregion

        #region 选中单元格的扩展事件

        /// <summary>
        /// 当选中改变并且点击单元格时触发
        /// </summary>
        [Description("当选中改变并且点击单元格时触发"), Category("ZCGridView"), Browsable(true)]
        public event DataGridViewCellEventHandler SelectionChangedAndCellClick;

        bool IsSelectChange; //是否选中改变

        void SetSelectionAndClickEvent(DataGridViewCellEventArgs e)
        {
            if (IsSelectChange)
            {
                if (SelectedRows.Count > 0)
                {
                    LastSelectionRowIndex = SelectedRows[0].Index;
                }
                else
                {
                    LastSelectionRowIndex = -1;
                }
                IsSelectChange = false;
                SelectionChangedAndCellClick?.Invoke(this, e);
            }
        }

        #endregion

        #region 列操作

        /// <summary>
        /// 创建一个GridView的文本框列
        /// </summary>
        /// <param name="text">标题</param>
        /// <param name="pName">数据源名称</param>
        /// <returns></returns>
        public static DataGridViewTextBoxColumn CreateTextBox(string text, string pName)
        {
            return new DataGridViewTextBoxColumn { HeaderText = text, DataPropertyName = pName };
        }
        /// <summary>
        /// 创建一个GridView的CheckBox
        /// </summary>
        public static DataGridViewColumn CreateCheckBox(string text, string pName)
        {
            return new DataGridViewCheckBoxColumn { HeaderText = text, DataPropertyName = pName };
        }
        /// <summary>
        /// 根据枚举创建Grid列
        /// </summary>
        public DataGridViewColumn CreateColumn(DgvColumnType colType, string title, string columnName)
        {
            DataGridViewColumn dgvCol;
            switch (colType)
            {
                case DgvColumnType.CheckBox:
                    dgvCol = CreateCheckBox(title, columnName);
                    break;
                case DgvColumnType.TextBox:
                default:
                    dgvCol = CreateTextBox(title, columnName);
                    break;
            }
            dgvCol.DataPropertyName = columnName;
            return dgvCol;
        }
        /// <summary>
        /// 根据 DgvColumnType 枚举名称创建Grid列
        /// </summary>
        public DataGridViewColumn CreateColumn(string colTypeStr, string title, string columnName)
        {
            EnumHelper.StringToEnum(colTypeStr, out DgvColumnType colType);
            return CreateColumn(colType, title, columnName);
        }


        #endregion

        

        #region 设置拖动更换事件

        int DorpMoveColumnIndex = -2;
        int DorpMoveRowIndex = -1;

        Action<int, int> OnDropMoveHandle;

        public void SetDropMove<TData>(Action<TData, TData> DropMoveHandle) where TData : class, new()
        {
            SetDropMove(-1, DropMoveHandle);
        }

        public void SetDropMove<TData>(int columnIndex, Action<TData, TData> DropMoveHandle)
        where TData : class, new()
        {
            SetDropMove(columnIndex, (mRowIndex, tRowIndex) =>
            {
                var m = GetSelectedClassData<TData>(mRowIndex);
                var t = GetSelectedClassData<TData>(tRowIndex);
                DropMoveHandle(m, t);
            });
        }

        /// <summary>
        /// 设置拖动事件
        /// </summary>
        public void SetDropMove(int columnIndex, Action<int, int> DropMoveHandle)
        {
            DorpMoveColumnIndex = columnIndex;
            OnDropMoveHandle = DropMoveHandle;

            this.MouseUp -= Dgv_MouseUp;
            this.MouseUp += Dgv_MouseUp;

            this.CellMouseDown -= Dgv_CellMouseDown;
            this.CellMouseDown += Dgv_CellMouseDown;

            this.CellMouseUp -= Dgv_CellMouseUp;
            this.CellMouseUp += Dgv_CellMouseUp;
        }
        /// <summary>
        /// 鼠标抬起 进行拖动释放的事件
        /// </summary>
        private void Dgv_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (RowCount < 2 ||
                //DorpMoveColumnIndex < 0 ||
                e.ColumnIndex != DorpMoveColumnIndex ||
                e.RowIndex < 0 ||
                DorpMoveRowIndex < 0 ||
                e.RowIndex == DorpMoveRowIndex
                ) return;
            OnDropMoveHandle(DorpMoveRowIndex, e.RowIndex);
        }
        /// <summary>
        /// 鼠标按下,进行拖动
        /// </summary>
        private void Dgv_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (RowCount < 2 ||
                //DorpMoveColumnIndex < 0 ||
                e.ColumnIndex != DorpMoveColumnIndex ||
                e.RowIndex < 0
                ) return;

            this.Cursor = Cursors.Hand;
            DorpMoveRowIndex = e.RowIndex;
        }
        /// <summary>
        /// 鼠标抬起,初始化光标及索引
        /// </summary>
        private void Dgv_MouseUp(object sender, MouseEventArgs e)
        {
            DorpMoveRowIndex = -1;
            this.Cursor = Cursors.Default;
        }

        #endregion

        #region 增加指定单元格按钮

        class ButtonColumnArg
        {
            public int ColumnIndex { set; get; }

            public Action<object, DataGridViewCellEventArgs> OnClickHandle;

            public string ColumnName { set; get; }
        }
        /// <summary>
        /// key为列名
        /// </summary>
        Dictionary<string, ButtonColumnArg> ButtonColumnList { get; } = new Dictionary<string, ButtonColumnArg>();

        ///// <summary>
        ///// 增加一个按钮列，并赋值点击事件，但点击事件不返回 Cell 信息
        ///// </summary>
        //public DataGridViewButtonColumn AddButtonColumn(string colName, Action<object> OnClickHandle)
        //{
        //    return AddButtonColumn(colName, (m, e) => OnClickHandle(m));
        //}
        /// <summary>
        /// 增加一个按钮列，并赋值点击事件，但点击事件不返回 Cell 信息
        /// </summary>
        public DataGridViewButtonColumn AddButtonColumn<TModel>(string colName, Action<TModel> OnClickHandle)
            where TModel : class, new()
        {
            return AddButtonColumn(colName, (m, e) => OnClickHandle(m as TModel));
        }
        /// <summary>
        /// 增加一个按钮列，并赋值点击事件，但点击事件返回 Cell
        /// </summary>
        public DataGridViewButtonColumn AddButtonColumn<TModel>(string colName, Action<TModel, DataGridViewCellEventArgs> OnClickHandle)
            where TModel : class, new()
        {
            return AddButtonColumn(colName, (m, e) => OnClickHandle(m as TModel, e));
        }
        /// <summary>
        /// 增加一个按钮列，并赋值点击事件
        /// 如果显示文本与列名不一致，返回列对象进行修改
        /// </summary>
        public DataGridViewButtonColumn AddButtonColumn(string colName, Action<object, DataGridViewCellEventArgs> OnClickHandle)
        {
            //初始化按钮
            var colButton = new DataGridViewButtonColumn();
            colButton.HeaderText = string.Empty;
            colButton.Text = colName;
            colButton.Name = colName;
            colButton.DefaultCellStyle.NullValue = colName;
            int index = this.Columns.Add(colButton);
            ButtonColumnList[colName] = new ButtonColumnArg
            {
                ColumnName = colName,
                ColumnIndex = index,
                OnClickHandle = OnClickHandle
            };
            return colButton;
        }

        void SetButtonClickEvent(DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0 || e.ColumnIndex < 0) return;
            if (ButtonColumnList == null) return;
            string colName = Columns[e.ColumnIndex].Name;
            if (!ButtonColumnList.ContainsKey(colName)) return;
            var m = GetSelectedItemData(e.RowIndex);
            ButtonColumnList[colName].OnClickHandle?.Invoke(m, e);
        }

        #endregion

        #region 点击单元格选中复选框

        /// <summary>
        /// 是否 点击单元格选中复选框
        /// </summary>
        [Description("单元格点击是否对CheckBox进行赋值"), Category("ZCGridView"), Browsable(true)]
        public bool CheckBoxCellClick { set; get; }

        void SetCheckBoxCellClickEvent(DataGridViewCellEventArgs e)
        {
            if (!CheckBoxCellClick) return;

            if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
            {
                if (Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn chBox)
                {
                    if (chBox.ReadOnly) return;

                    if (chBox.TrueValue == null) chBox.TrueValue = true;
                    if (chBox.FalseValue == null) chBox.FalseValue = false;

                    var cellValue = GetCellValue(e.RowIndex, e.ColumnIndex);
                    if (cellValue.Equals(chBox.TrueValue))
                    {
                        SetCellValue(e.RowIndex, e.ColumnIndex, chBox.FalseValue);
                    }
                    else
                    {
                        SetCellValue(e.RowIndex, e.ColumnIndex, chBox.TrueValue);
                    }
                    EndEdit();
                }
            }
        }

        #endregion

        #region 合并单元格

        //关于画单元格的实现可参考：https://group.cnblogs.com/topic/40730.html

        //目前用控件附着的方式实现，更简单、方便、灵活（失败，白忙活了，改变大小之后错位不好处理）

        protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
        {
            DrawCell(e);
            base.OnCellPainting(e);
        }

        public class CellMergeScheme
        {
            /// <summary>
            /// 空置是否合并
            /// </summary>
            public bool NullMerge { set; get; } = false;
            /// <summary>
            /// 背景颜色
            /// </summary>
            public Color BackColor { set; get; } = Color.MintCream;
            /// <summary>
            /// 字体颜色
            /// </summary>
            public Color FontColor { set; get; } = Color.Green;
            /// <summary>
            /// 列名
            /// </summary>
            public string ColumnName { set; get; }
            /// <summary>
            /// 固定显示的文本，如：删除，等操作
            /// </summary>
            public string FixedText { set; get; }
            /// <summary>
            /// 合并验证处理委托(验证相同还需校验的方法) 首次参数为原model，第二个为当前model
            /// </summary>
            public Func<object, object, bool> MergeModelVerifyHandle { set; get; }

            //public Func<DataGridViewCell, DataGridViewCell, bool> MergeCellVerifyHandle { set; get; }

            public bool MergeCellVerify(DataGridViewCell srcCell, DataGridViewCell tarCell)
            {
                if (!NullMerge && (srcCell.Value == null || tarCell.Value == null))
                {
                    return false;
                }
                if (srcCell.Value == null)
                {
                    srcCell.Value = string.Empty;
                }
                if (srcCell.Value == null)
                {
                    srcCell.Value = string.Empty;
                }

                if (srcCell.Value.Equals(tarCell.Value))
                {
                    var dgv = srcCell.DataGridView as GridView;
                    if (MergeModelVerifyHandle != null)
                    {
                        var srcObj = dgv.GetSelectedItemData(srcCell.RowIndex);
                        var tarObj = dgv.GetSelectedItemData(tarCell.RowIndex);
                        return MergeModelVerifyHandle(srcObj, tarObj);
                    }
                    return true;
                }
                return false;
            }

            public Dictionary<int, string> RowSpan { get; } = new Dictionary<int, string>();

            public void AddRowSpan(int sRowIndex, int eRowIndex)
            {
                string sign = null;
                foreach (var item in RowSpan)
                {
                    if (item.Key >= sRowIndex && item.Key <= eRowIndex)
                    {
                        sign = item.Value;
                        break;
                    }
                }
                if (sign == null) sign = Guid.NewGuid().ToString();
                for (int i = sRowIndex; i <= eRowIndex; i++)
                {
                    RowSpan[i] = sign;
                }
            }

            public void ClearRowSpan()
            {
                RowSpan.Clear();
            }

            public int[] GetRowIndex(int rowIndex)
            {
                var sign = RowSpan[rowIndex];
                var r = RowSpan.Where(s => s.Value == sign).Select(s => s.Key).ToArray();
                return r;
            }

            /// <summary>
            /// 合并单元格点击事件
            /// </summary>
            public Action<object> MergeCellClickHandle { set; get; }
        }

        List<CellMergeScheme> CellMergeList { get; } = new List<CellMergeScheme>();

        public void AddMergeColumn(CellMergeScheme scheme)
        {
            if (CellMergeList.Exists(s => s.ColumnName == scheme.ColumnName)) return;
            CellMergeList.Add(scheme);
        }

        public void AddMergeColumn(string colName, bool nullMerge = false)
        {
            AddMergeColumn<object>(colName, null, null, null, nullMerge);
        }

        public void AddMergeColumn<TRowData>(
            string colName,
            Func<TRowData, TRowData, bool> MergeVerify,
            string fixedText = null,
            Action<TRowData> MergeCellClick = null,
            bool nullMerge = false)
            where TRowData : class, new()
        {
            if (CellMergeList.Exists(s => s.ColumnName == colName)) return;

            var scheme = new CellMergeScheme
            {
                ColumnName = colName,
                NullMerge = nullMerge,
                FixedText = fixedText
            };
            if (MergeVerify != null)
            {
                scheme.MergeModelVerifyHandle =
                    (sObj, tObj) =>
                    {
                        return MergeVerify(sObj as TRowData, tObj as TRowData);
                    };
            }
            if (MergeCellClick != null)
            {
                scheme.MergeCellClickHandle = (obj) => MergeCellClick(obj as TRowData);
            }
            CellMergeList.Add(scheme);
        }

        /// <summary>
        /// 画单元格
        /// </summary>
        private void DrawCell(DataGridViewCellPaintingEventArgs e)
        {
            if (e.RowIndex < 0 || e.ColumnIndex < 0 || RowCount == 0) return;

            if (CellMergeList.Count == 0) return;

            var arg = CellMergeList.Find(s => s.ColumnName == Columns[e.ColumnIndex].Name);
            if (arg == null) return;

            //上面相同的行数,下面相同的行，总行数
            int upRows = 0, downRows = 0, count = 0;

            if (e.RowIndex == 0) arg.RowSpan.Clear();

            // 获取下面的行数
            for (int i = e.RowIndex + 1; i < Rows.Count; i++)
            {
                if (arg.MergeCellVerify(Rows[i].Cells[e.ColumnIndex], Rows[e.RowIndex].Cells[e.ColumnIndex]))
                {
                    downRows++;
                }
                else break;
            }
            // 获取上面的行数
            for (int i = e.RowIndex - 1; i >= 0; i--)
            {
                if (arg.MergeCellVerify(Rows[i].Cells[e.ColumnIndex], Rows[e.RowIndex].Cells[e.ColumnIndex]))
                {
                    upRows++;

                }
                else break;
            }

            count = downRows + upRows + 1;

            arg.AddRowSpan(e.RowIndex - upRows, e.RowIndex + downRows);

            SolidBrush backBrush = new SolidBrush(arg.BackColor);

            //以背景色填充
            e.Graphics.FillRectangle(backBrush, e.CellBounds);

            string cellText = arg.FixedText ?? e.Value?.ToString();

            //画字符串
            int fontwidth = (int)e.Graphics.MeasureString(cellText, e.CellStyle.Font).Width;
            int fontheight = (int)e.Graphics.MeasureString(cellText, e.CellStyle.Font).Height;
            int cellwidth = e.CellBounds.Width;
            int cellheight = e.CellBounds.Height;
            SolidBrush fontBrush = new SolidBrush(arg.FontColor);
            e.Graphics.DrawString(
                cellText,
                e.CellStyle.Font, fontBrush,
                e.CellBounds.X + (cellwidth - fontwidth) / 2,
                e.CellBounds.Y - cellheight * upRows + (cellheight * count - fontheight) / 2);

            Pen gridLinePen = new Pen(this.GridColor);
            if (downRows == 0)
            {
                //下面线
                e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
            }
            // 画右边线
            e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1, e.CellBounds.Top, e.CellBounds.Right - 1, e.CellBounds.Bottom);

            e.Handled = true;

            backBrush.Dispose();
            fontBrush.Dispose();
            gridLinePen.Dispose();
        }

        private void MergeSelected(DataGridViewCellEventArgs e)
        {
            if (CellMergeList.Count == 0) return;
            var colName = Columns[e.ColumnIndex].Name;
            var arg = CellMergeList.Find(s => s.ColumnName == colName);
            if (arg == null) return;
            if (e.RowIndex < 0) return;
            var rows = arg.GetRowIndex(e.RowIndex);
            for (int i = 0; i < RowCount; i++)
            {
                SetSelectedRowCore(i, rows.Contains(i));
            }
            if (arg.MergeCellClickHandle != null)
            {
                var obj = GetSelectedItemData(e.RowIndex);
                arg.MergeCellClickHandle(obj);
            }
        }

        #endregion

        #region 设置分组大括号

        // 

        Dictionary<string, string> BraceGroupConf { get; set; }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawBraceGroup(e);
        }
        /// <summary>
        /// 增加相同分组的大括号
        /// </summary>
        /// <param name="groupColumnName">显示分组的列名</param>
        /// <param name="groupPropertyName">分组依据的属性名名</param>
        public void AddBraceGroup(string groupColumnName, string groupPropertyName)
        {
            if (BraceGroupConf == null) BraceGroupConf = new Dictionary<string, string>();

            BraceGroupConf[groupColumnName] = groupPropertyName;
        }

        void DrawBraceGroup(PaintEventArgs e)
        {
            if (BraceGroupConf == null || BraceGroupConf.Count == 0) return;

            int startRow;
            string lastVal;

            foreach (var item in BraceGroupConf)
            {
                startRow = -1;
                lastVal = null;

                var viewName = item.Key;
                var proName = item.Value;
                var displayColumnIndex = this.GetColumnByPropertyName(viewName).Index;

                for (int i = 0; i < RowCount; i++)
                {
                    var obj = GetSelectedItemData(i);
                    var currVal = ReflectionHelper.GetPropertyValue(obj, proName)?.ToString();
                    if (currVal.IsNotEmpty() && startRow == -1)
                    {
                        lastVal = currVal;
                        startRow = i;
                        continue;
                    }

                    if (startRow < 0) continue;

                    if (!currVal.StringEquals(lastVal))
                    {
                        if (i - startRow > 1)
                        {
                            DrawBrace(startRow, i - 1, displayColumnIndex, e);
                        }

                        if (currVal.IsNotEmpty())
                        {
                            startRow = i;
                            lastVal = currVal;
                        }
                        else
                        {
                            startRow = -1;
                            lastVal = null;
                        }
                        continue;
                    }
                }
                if (startRow >= 0 && RowCount - startRow > 1)
                {
                    DrawBrace(startRow, RowCount - 1, displayColumnIndex, e);
                }
            }
        }

        /// <summary>
        /// 绘制花括号   DrawBrace(1, 1, 3, 1, e);
        /// 2023.9.27 by jzd
        /// </summary>
        /// <param name="startRowIndex">起始单元格行索引</param>
        /// <param name="startColumnIndex">起始单元格列索引</param>
        /// <param name="endRowIndex">结束单元格行索引</param>
        /// <param name="endColumnIndex">结束单元格列索引</param>
        public void DrawBrace(int startRowIndex, int endRowIndex, int columnIndex, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.FromArgb(0, 0, 0), 3);
            pen.Color = Color.BlueViolet;
            pen.DashStyle = DashStyle.Solid;//虚线的样式

            Graphics g = e.Graphics;

            //轨迹始止坐标

            var xStart = GetCellDisplayRectangle(columnIndex, startRowIndex, false).X - 2 * pen.Width;
            var yStart = GetCellDisplayRectangle(columnIndex, startRowIndex, false).Y;

            var xEnd = GetCellDisplayRectangle(columnIndex, endRowIndex, false).X - 2 * pen.Width;
            var yEnd = GetCellDisplayRectangle(columnIndex, endRowIndex, false).Y + this.GetCellDisplayRectangle(columnIndex, endRowIndex, false).Height;

            #region 花括号“{”的轨迹

            var xMiddleStart1 = xStart;
            var yMiddleStart1 = yStart + (yEnd - yStart) / 2 - pen.Width;
            var xMiddleEnd1 = xStart - pen.Width;
            var yMiddleEnd11 = yStart + (yEnd - yStart) / 2;


            var xMiddleStart2 = xStart - pen.Width;
            var yMiddleStart2 = yStart + (yEnd - yStart) / 2;
            var xMiddleEnd2 = xStart;
            var yMiddleEnd12 = yStart + (yEnd - yStart) / 2 + pen.Width;

            using (GraphicsPath myPath = new GraphicsPath())
            {
                RectangleF rectangle = new RectangleF(xStart, yStart, 2 * 2 * pen.Width, 2 * 2 * pen.Width);
                myPath.AddArc(rectangle, -90, -90);
                PointF[] points1 = { new PointF(xStart, yStart + 2 * pen.Width), new PointF(xMiddleStart1, yMiddleStart1) };
                myPath.AddLine(points1[0], points1[1]);
                PointF[] points2 = { new PointF(xMiddleStart1, yMiddleStart1), new PointF(xMiddleEnd1, yMiddleEnd11) };
                myPath.AddLine(points2[0], points2[1]);
                PointF[] points3 = { new PointF(xMiddleStart2, yMiddleStart2), new PointF(xMiddleEnd2, yMiddleEnd12) };
                myPath.AddLine(points3[0], points3[1]);
                PointF[] points4 = { new PointF(xMiddleEnd2, yMiddleEnd12), new PointF(xEnd, yEnd - 2 * pen.Width) };
                myPath.AddLine(points4[0], points4[1]);
                RectangleF rectangle2 = new RectangleF(xEnd, yEnd - 2 * 2 * pen.Width, 2 * 2 * pen.Width, 2 * 2 * pen.Width);
                myPath.AddArc(rectangle2, -180, -90);

                #endregion
                g.DrawPath(pen, myPath);
            }
        }

        #endregion
    }

    /// <summary>
    /// 列类型
    /// </summary>
    public enum DgvColumnType
    {
        /// <summary>
        /// 文本框（默认）
        /// </summary>
        TextBox,
        /// <summary>
        /// 复选框
        /// </summary>
        CheckBox,
        /// <summary>
        /// 下拉列表
        /// </summary>
        ComboBox,
    }


}
